/******************************************************************************
 * Copyright (c) 2013-2016 Realtek Semiconductor Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/


#ifndef _RTW_PSK_H_
#define _RTW_PSK_H_

#define GMK_LEN 32
#define GTK_LEN 32
#define IGTK_LEN 16
#define PMK_LEN 32
#define KEY_NONCE_LEN 32
#define NumGroupKey 4
#define KEY_RC_LEN 8
#define KEY_IV_LEN 16
#define KEY_RSC_LEN 8
#define KEY_ID_LEN 8
#define KEY_MIC_LEN 16
#define KEY_MATERIAL_LEN 2
#define PTK_LEN_EAPOLMIC 16
#define PTK_LEN_EAPOLENC 16
#define PTK_LEN_TKIP 64
#define PTK_LEN_CCMP 48
#define LIB1X_ETHER_EAPOL_TYPE 0x888E

#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_LEN 16
#define WPA_IGTK_MAX_LEN 32
#endif /* CONFIG_IEEE80211W */

#define DescTypePos 0
#define KeyInfoPos 1
#define KeyLenPos 3
#define ReplayCounterPos 5
#define KeyNoncePos 13
#define KeyIVPos 45
#define KeyRSCPos 61
#define KeyIDPos 69
#define KeyMICPos 77
#define KeyDataLenPos 93
#define KeyDataPos 95
#define LIB1X_EAPOL_VER 1		  //0000 0001B
#define LIB1X_EAPOL_EAPPKT 0	  //0000 0000B
#define LIB1X_EAPOL_START 1		  //0000 0001B
#define LIB1X_EAPOL_LOGOFF 2	  //0000 0010B
#define LIB1X_EAPOL_KEY 3		  //0000 0011B
#define LIB1X_EAPOL_ENCASFALERT 4 //0000 0100B

#define A_SHA_DIGEST_LEN 20
#define ETHER_HDRLEN 14
#define LIB1X_EAPOL_HDRLEN 4
#define INFO_ELEMENT_SIZE 128
#define MAX_EAPOLMSG_LEN 512
#define MAX_EAPOLKEYMSG_LEN (MAX_EAPOLMSG_LEN - (ETHER_HDRLEN + LIB1X_EAPOL_HDRLEN))
#define EAPOLMSG_HDRLEN 95 //EAPOL-key payload length without KeyData
#define WPA_ELEMENT_ID 0xDD
#define WPA2_ELEMENT_ID 0x30

#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

#define ETHER_ADDRLEN 6
#define PMK_EXPANSION_CONST "Pairwise key expansion"
#define PMK_EXPANSION_CONST_SIZE 22
#define GMK_EXPANSION_CONST "Group key expansion"
#define GMK_EXPANSION_CONST_SIZE 19
#define IGTK_EXPANSION_CONST "IGTK key expansion"
#define RANDOM_EXPANSION_CONST "Init Counter"
#define RANDOM_EXPANSION_CONST_SIZE 12

#define WLAN_REASON_MIC_FAILURE 14
#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15

#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
#define WPA_KEY_MGMT_NONE BIT(2)
#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
#define WPA_KEY_MGMT_WPA_NONE BIT(4)
#define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
#define WPA_KEY_MGMT_FT_PSK BIT(6)
#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
#define WPA_KEY_MGMT_WPS BIT(9)
#define WPA_KEY_MGMT_SAE BIT(10)
#define WPA_KEY_MGMT_FT_SAE BIT(11)
#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
#define WPA_KEY_MGMT_CCKM BIT(14)
#define WPA_KEY_MGMT_OSEN BIT(15)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)

/*
	2008-12-16, For Corega CG-WLCB54GL 54Mbps NIC interoperability issue.
	The behavior of this NIC when it connect to the other AP with WPA/TKIP is:
		AP<----------------------> STA
			....................
			------------> Assoc Rsp (ok)
			------------> EAPOL-key (4-way msg 1)
			<------------ unknown TKIP encryption data
			------------> EAPOL-key (4-way msg 1)
			<------------ unknown TKIP encryption data
			.....................
			<------------ disassoc (code=8, STA is leaving) when the 5 seconds timer timeout counting from Assoc_Rsp is got.
			....................
			------------> Assoc Rsp (ok)
			<-----------> EAPOL-key (4-way handshake success)

	If MAX_RESEND_NUM=3, our AP will send disassoc (code=15, 4-way timeout) to STA before STA sending disassoc to AP.
	And this NIC will always can not connect to our AP.
	set MAX_RESEND_NUM=5 can fix this issue.
 */
#define MAX_RESEND_NUM 5

/*
	Revise STA EAPOL-key(4-2) resend time from "RESEND_TIME" to "CLIENT_RESEND_TIME" to make sure one 4-1 followed
	by only one 4-2 but not 'several' to fix:
	As to AP "HUAWEI WS5100", in case of situation that if STA (re)connect to the AP with a wrong password for several times
	and in each (re)connect the 4-2 msg with the wrong pw info (re)sent more than once in response to every 4-1, then the AP will
	probably put the STA into blacklist and won't respond to STA's AUTH again even the STA may has corrected the password.

	AP(WS5100) < ----------->STA
					....................
					------------> Assoc Rsp (ok)
					------------> EAPOL-key (4-1)
					<------------ EAPOL-key (4-2 with wrong pw info)
					<------------ EAPOL-key (resend 4-2 with wrong pw info)

					------------> EAPOL-key (4-way msg 1)
					<------------ EAPOL-key (4-2 with wrong pw info)
					<------------ EAPOL-key (resend 4-2 with wrong pw info)
					....................
*/
#define RESEND_TIME 1000
#define CLIENT_RESEND_TIME 1200
#define WAIT_TIME 7000

#define GK_REKEY_TIME 3600000 //Set rekey period to 1 hour

					   typedef enum {
						   desc_type_RSN = 2,
						   desc_type_WPA = 254
					   } DescTypeRSN;

typedef enum {
	type_Group = 0,
	type_Pairwise = 1
} KeyType;

typedef enum {
	key_desc_ver1 = 1,
	key_desc_ver2 = 2,
	key_desc_ver3 = 3 //AES_128_CMAC, for 802.11w
} KeyDescVer;

enum {
	PSK_WPA = 1,
	PSK_WPA2 = 2
};

enum {
	PSK_STATE_IDLE,
	PSK_STATE_PTKSTART,
	PSK_STATE_PTKINITNEGOTIATING,
	PSK_STATE_PTKINITDONE,
};

enum {
	PSK_GSTATE_REKEYNEGOTIATING,
	PSK_GSTATE_REKEYESTABLISHED,
	PSK_GSTATE_KEYERROR,
};

typedef struct _OCTET_STRING {
	unsigned char *Octet;
	int Length;
} OCTET_STRING;

typedef union _LARGE_INTEGER {
	unsigned char charData[8];
	struct {
		unsigned int HighPart;
		unsigned int LowPart;
	} field;
} LARGE_INTEGER, *PLARGE_INTEGER;

typedef union _OCTET16_INTEGER {
	unsigned char charData[16];
	struct {
		LARGE_INTEGER HighPart;
		LARGE_INTEGER LowPart;
	} field;
} OCTET16_INTEGER;

typedef union _OCTET32_INTEGER {
	unsigned char charData[32];
	struct {
		OCTET16_INTEGER HighPart;
		OCTET16_INTEGER LowPart;
	} field;
} OCTET32_INTEGER;

#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_KDE_PREFIX_LEN (2 + 6)
struct wpa_igtk_kde {
	u8 keyid[2];
	u8 pn[6];
	u8 igtk[WPA_IGTK_MAX_LEN];
};
#endif /* CONFIG_IEEE80211W */

// group key info
typedef struct _wpa_global_info {
	OCTET32_INTEGER Counter;
	//Save PSK to global array
	int GTKAuthenticator;
	int GKeyDoneStations;
	int GInitAKeys;
	int GUpdateStationKeys;
	int GkeyReady;
	OCTET_STRING AuthInfoElement;
	unsigned char AuthInfoBuf[INFO_ELEMENT_SIZE];
	unsigned char MulticastCipher;
	unsigned int AuthKeyMgmt; // add for 802.11w
	OCTET_STRING GNonce;
	unsigned char GNonceBuf[KEY_NONCE_LEN];
	unsigned char GTK[NumGroupKey][GTK_LEN];
	unsigned char GMK[GMK_LEN];
	int GN;
	int GM;
	int GTKRekey;
#ifdef CONFIG_GK_REKEY
	struct timer_list GKRekeyTimer;
#endif

#ifdef CONFIG_IEEE80211W
	unsigned char IGTK_IPN[2][8];
	unsigned char IGTK[2][WPA_IGTK_MAX_LEN];
	int GN_igtk;
	int GM_igtk;
	int IGTK_len;
#endif
} WPA_GLOBAL_INFO;

// wpa sta info
typedef struct _wpa_sta_info {
	int state;
	int gstate;
	int RSNEnabled; // bit0-WPA, bit1-WPA2
	int PInitAKeys;
	unsigned char UnicastCipher;
	LARGE_INTEGER CurrentReplayCounter;
	LARGE_INTEGER ReplayCounterStarted; // david+1-12-2007
	OCTET_STRING ANonce;
	OCTET_STRING SNonce;
	unsigned char AnonceBuf[KEY_NONCE_LEN];
	unsigned char SnonceBuf[KEY_NONCE_LEN];
	unsigned char PMK[PMK_LEN];
	unsigned char PTK[PTK_LEN_TKIP];
	OCTET_STRING EAPOLMsgRecvd;
	OCTET_STRING EAPOLMsgSend;
	OCTET_STRING EapolKeyMsgRecvd;
	OCTET_STRING EapolKeyMsgSend;

	unsigned char eapSendBuf[MAX_EAPOLMSG_LEN];
	struct timer_list resendTimer;
	int resendCnt;
	struct timer_list waitTimer; // wait for 4-1 or 2-1
	int clientHndshkProcessing;
	int clientHndshkDone;
	int clientGkeyUpdate;
	LARGE_INTEGER clientMICReportReplayCounter;
} WPA_STA_INFO;

typedef struct _LIB1X_EAPOL_KEY {
	unsigned char key_desc_ver;
	unsigned char key_info[2];
	unsigned char key_len[2];
	unsigned char key_replay_counter[KEY_RC_LEN];
	unsigned char key_nounce[KEY_NONCE_LEN];
	unsigned char key_iv[KEY_IV_LEN];
	unsigned char key_rsc[KEY_RSC_LEN];
	unsigned char key_id[KEY_ID_LEN];
	unsigned char key_mic[KEY_MIC_LEN];
	unsigned char key_data_len[KEY_MATERIAL_LEN];
	unsigned char *key_data;
} lib1x_eapol_key;

struct lib1x_eapol {
	unsigned char protocol_version;
	unsigned char packet_type; // This makes it odd in number !
	unsigned short packet_body_length;
};

struct wlan_ethhdr_t {
	unsigned char daddr[WLAN_ETHADDR_LEN];
	unsigned char saddr[WLAN_ETHADDR_LEN];
	unsigned short type;
};

typedef enum {
	DOT11_PortStatus_Unauthorized,
	DOT11_PortStatus_Authorized,
	DOT11_PortStatus_Guest
} DOT11_PORT_STATUS;

#ifdef CONFIG_MOVE_PSK_TO_ROM
static __inline__ OCTET_STRING SubStr(OCTET_STRING f, unsigned short s, unsigned short l)
{
	OCTET_STRING res;

	res.Length = l;
	res.Octet = f.Octet + s;

	return res;
}
#endif

#define SetSubStr(f, a, l) memcpy(f.Octet + l, a.Octet, a.Length)
#define GetKeyInfo0(f, mask) ((f.Octet[KeyInfoPos + 1] & mask) ? 1 : 0)
#define SetKeyInfo0(f, mask, b) (f.Octet[KeyInfoPos + 1] = (f.Octet[KeyInfoPos + 1] & ~mask) | (b ? mask : 0x0))
#define GetKeyInfo1(f, mask) ((f.Octet[KeyInfoPos] & mask) ? 1 : 0)
#define SetKeyInfo1(f, mask, b) (f.Octet[KeyInfoPos] = (f.Octet[KeyInfoPos] & ~mask) | (b ? mask : 0x0))

// EAPOLKey
#define Message_DescType(f) (f.Octet[DescTypePos])
#define Message_setDescType(f, type) (f.Octet[DescTypePos] = type)
// Key Information Filed
#define Message_KeyDescVer(f) (f.Octet[KeyInfoPos + 1] & 0x07)
#define Message_setKeyDescVer(f, v) (f.Octet[KeyInfoPos + 1] &= 0xf8), f.Octet[KeyInfoPos + 1] |= (v & 0x07)
#define Message_KeyType(f) GetKeyInfo0(f, 0x08)
#define Message_setKeyType(f, b) SetKeyInfo0(f, 0x08, b)
#define Message_KeyIndex(f) ((f.Octet[KeyInfoPos + 1] & 0x30) >> 4) & 0x03
#define Message_setKeyIndex(f, v) (f.Octet[KeyInfoPos + 1] &= 0xcf), f.Octet[KeyInfoPos + 1] |= ((v << 4) & 0x30)
#define Message_setInstall(f, b) SetKeyInfo0(f, 0x40, b)
#define Message_setKeyAck(f, b) SetKeyInfo0(f, 0x80, b)

#define Message_KeyMIC(f) GetKeyInfo1(f, 0x01)
#define Message_setKeyMIC(f, b) SetKeyInfo1(f, 0x01, b)
#define Message_Secure(f) GetKeyInfo1(f, 0x02)
#define Message_setSecure(f, b) SetKeyInfo1(f, 0x02, b)
#define Message_Error(f) GetKeyInfo1(f, 0x04)
#define Message_setError(f, b) SetKeyInfo1(f, 0x04, b)
#define Message_Request(f) GetKeyInfo1(f, 0x08)
#define Message_setRequest(f, b) SetKeyInfo1(f, 0x08, b)
#define Message_setReserved(f, v) (f.Octet[KeyInfoPos] |= (v << 4 & 0xff))
#define Message_KeyLength(f) ((unsigned short)(f.Octet[KeyLenPos] << 8) + (unsigned short)(f.Octet[KeyLenPos + 1]))
#define Message_setKeyLength(f, v) (f.Octet[KeyLenPos] = (v & 0xff00) >> 8, f.Octet[KeyLenPos + 1] = (v & 0x00ff))

#define Message_KeyNonce(f) SubStr(f, KeyNoncePos, KEY_NONCE_LEN)
#define Message_setKeyNonce(f, v) SetSubStr(f, v, KeyNoncePos)
#define Message_EqualKeyNonce(f1, f2) memcmp(f1.Octet + KeyNoncePos, f2.Octet, KEY_NONCE_LEN) ? 0 : 1
#define Message_setKeyIV(f, v) SetSubStr(f, v, KeyIVPos)
#define Message_setKeyRSC(f, v) SetSubStr(f, v, KeyRSCPos)
#define Message_setKeyID(f, v) SetSubStr(f, v, KeyIDPos)
#define Message_setMIC(f, v) SetSubStr(f, v, KeyMICPos)
#define Message_KeyDataLength(f) ((unsigned short)(f.Octet[KeyDataLenPos] << 8) + (unsigned short)(f.Octet[KeyDataLenPos + 1]))
#define Message_setKeyDataLength(f, v) (f.Octet[KeyDataLenPos] = (v & 0xff00) >> 8, f.Octet[KeyDataLenPos + 1] = (v & 0x00ff))
#define Message_setKeyData(f, v) SetSubStr(f, v, KeyDataPos);

#define Message_CopyReplayCounter(f1, f2) memcpy(f1.Octet + ReplayCounterPos, f2.Octet + ReplayCounterPos, KEY_RC_LEN)
#define Message_DefaultReplayCounter(li) (((li.field.HighPart == 0xffffffff) && (li.field.LowPart == 0xffffffff)) ? 1 : 0)

#define GET_MY_HWADDR(padapter) ((padapter)->eeprompriv.mac_addr)
#define LargeIntegerOverflow(x) (x.field.HighPart == 0xffffffff) && (x.field.LowPart == 0xffffffff)
#define LargeIntegerZero(x) memset(&x.charData, 0, 8)
#define Octet16IntegerOverflow(x) LargeIntegerOverflow(x.field.HighPart) && LargeIntegerOverflow(x.field.LowPart)
#define Octet16IntegerZero(x) memset(&x.charData, 0, 16)
#define SetNonce(ocDst, oc32Counter) SetEAPOL_KEYIV(ocDst, oc32Counter)

int wpa_key_mgmt_sha256(int akm);
void ClientSendEAPOL(_adapter *padapter, struct sta_info *psta, int resend);
void SendEAPOL(_adapter *padapter, struct sta_info *psta, int resend);
void EAPOLKeyRecvd(_adapter *padapter, struct sta_info *psta);
void ClientEAPOLKeyRecvd(_adapter *padapter, struct sta_info *psta);
void init_wpa_sta_info(_adapter *padapter, struct sta_info *psta);
void psk_init(_adapter *padapter, unsigned char *pie, unsigned short ielen);
void psk_derive(_adapter *padapter, unsigned char *passphrase, unsigned char *ssid);
u16 psk_strip_rsn_pairwise(u8 *ie, u16 ie_len);
u16 psk_strip_wpa_pairwise(u8 *ie, u16 ie_len);

#endif // _RTW_PSK_H_
